﻿#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)

#include <stdio.h>
#include <assert.h>

/* 实用调试技巧 */
//什么是bug？
//调试是什么？有多重要？
//debug和release的介绍。
//windows环境调试介绍。
//一些调试的实例。
//如何写出好（易于调试）的代码。
//编程常见的错误。

//2.2 调试的基本步骤
//1.发现程序错误的存在
//2.以隔离、消除等方式对错误进行定位
//3.确定错误产生的原因
//4.提出纠正错误的解决办法
//5.对程序错误予以改正，重新测试

//2.3 Debug和Release的介绍。
//Debug 通常称为调试版本，它包含调试信息，并且不作任何优化，便于程序员调试程序。
//Release 称为发布版本，它往往是进行了各种优化，使得程序在代码大小和运行速度上都是最优的，以便用户很好地使用。

//int main()
//{
//	char* p = "hello bit.";
//	printf("%s\n", p);
//	return 0;
//}

/* 3. Windows环境调试介绍 */
//最常使用的几个快捷键：
//F5
//启动调试，经常用来直接跳到下一个断点处。
//F9
//创建断点和取消断点
//断点的重要作用，可以在程序的任意位置设置断点。
//这样就可以使得程序在想要的位置随意停止执行，继而一步步执行下去。
//F10
//逐过程，通常用来处理一个过程，一个过程可以是一次函数调用，或者是一条语句。
//F11
//逐语句，就是每次都执行一条语句，但是这个快捷键可以使我们的执行逻辑进入函数内部（这是最
//长用的）。
//CTRL + F5
//开始执行不调试，如果你想让程序直接运行起来而不调试就可以直接使用。

//int main()
//{
//	int i = 0;
//	int arr[10] = { 0 };
//	//赋值
//	for (i = 0; i < 10; i++)
//	{
//		arr[i] = i;
//	}
//	//打印
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//
//	return 0;
//}


//3.3 调试的时候查看程序当前信息
//3.3.1 查看临时变量的值—在调试开始之后，用于观察变量的值。
//3.3.2 查看内存信息

//3.3.3 查看调用堆栈
//void test2()
//{
//	printf("dw");
//}
//void test1()
//{
//	test2();
//}
//void test()
//{
//	test1();
//}
//
//int main()
//{
//	test();
//	return 0;
//}

//数据结构中的栈
//往栈中放元素—压栈
//从栈中拿出一个元素—出栈


// 3.3.4 查看汇编信息
//int main()
//{
//	char arr[] = "abcdef";
//	printf("%s\n", arr);
//}

// 3.3.5 查看寄存器信息


/* 5. 调试的实例 */
//5.1 实现代码：求 1！+2！+3！ ...+ n! ；不考虑溢出。
//int main()
//{
//	int n = 0;
//	int ret = 1;//保存n的阶乘
//	scanf("%d", &n);
//	
//	int i = 0;
//	int sum = 0;//保存最终结果
//	for (i = 1; i <= n; i++)
//	{
//		ret = 1;		//通过调试分析问题
//		int j = 0;
//		for (j = 1; j <= i; j++)
//		{
//			ret *= j;		//ret = ret * j;
//		}
//		sum += ret;		//sum=sum+ret
//	}
//	printf("%d\n", sum);
//	return 0;
//}

//5.2
//int main()
//{
//	int i = 0;
//	int arr[10] = { 0 };
//	for (i = 0; i <= 12; i++)
//	{
//		arr[i] = 0;
//		printf("hehe\n");
//	}
//	return 0;
//}
//死循环

// 1.栈区内存的使用习惯是先使用高地址处的空间，再使用低地址处的空间
// 2.数组随着下标的增长，地址是由低到高变化的
// 3.如果i和arr之间有适当的空间，利用数组的越界操作 就可能会覆盖到i，就可能会导致死循环


//模拟实现库函数：strcpy
/***
* char *strcpy(dst, src) - copy one string over another
*
*Purpose:
*       Copies the string src into the spot specified by
*       dest; assumes enough room.
*
*Entry:
*       char * dst - string over which "src" is to be copied
*       const char * src - string to be copied over "dst"
*
*Exit:
*       The address of "dst"
*
*Exceptions:
*******************************************************************************/
#include <assert.h>

char* strcpy(char* dst, const char* src)		//返回char*是为了实现链式访问， strcpy函数返回的是目标空间的起始地址
{
	char* cp = dst;
	assert(dst && src);		//assert断言，如果()中的表达式为假，assert就报错

	while (*dst++ = *src++)
		; 
	return(cp);
}
//strcpy在拷贝字符串时，会把源字符串的\0也拷贝过去


//6.3 const的作用
//代码1
//void test1()
//{
//	int n = 10;
//	int m = 20;
//	int* p = &n;
//	*p = 20;//ok
//	p = &m; //ok
//}
//void test2()
//{
//	//代码2
//	int n = 10;
//	int m = 20;
//	const int* p = &n;		//const int* p <==> int const* p
//	//*p = 20;//err
//	p = &m; //ok
//}
//void test3()
//{
//	int n = 10;
//	int m = 20;
//	int* const p = &n;
//	*p = 20; //ok
//	//p = &m;  //err
//}
//int main()
//{
//	//测试无cosnt的
//	test1();
//	//测试const放在*的左边
//	test2();
//	//测试const放在*的右边
//	test3();
//	return 0;
//}

//结论：
//const修饰指针变量的时候：
//1. const如果放在 * 的左边，限制的是指针指向的内容，保证指针指向的内容不能通过指针来改变。但是指针变量本身的内容可变。
//2. const如果放在 * 的右边，限制的是指针变量本身，保证了指针变量的内容不能修改，但是指针指向的内容，可以通过指针改变。


/* 模拟实现一个strlen函数-求字符串长度的函数 */
//int my_strlen(const char* str)		//加const为了str指向的元素不能被修改
//{
//	int count = 0;
//	assert(str != NULL);		//为了防止万一while中的str为空指针，所以加个assert
//	while (*str != '\0')//判断字符串是否结束
//	{
//		count++;
//		str++;
//	}
//	return count;
//}
//int main()
//{
//	const char* p = "abcdef";		//等价于char p[]= "abcdef";
//	//测试
//	int len = my_strlen(p);
//	printf("len = %d\n", len);
//	return 0;
//}


//7. 编程常见的错误

//7.1 编译型错误（语法错误）：直接看错误提示信息（双击），解决问题。或者凭借经验就可以搞定。相对来说简单。

//7.2 链接型错误：看错误提示信息，主要在代码中找到错误信息中的标识符，然后定位问题所在。一般是标识符名不存在或者拼写错误。

//7.3 运行时错误借助调试，逐步定位问题。最难搞。

//温馨提示：
//做一个有心人，积累排查经验。
//讲解重点：
//介绍每种错误怎么产生，出现之后如何解决。